package core 

import (
	"fmt"
	"gim/db"
	"gim/mq"
	"gim/storage"
	"gim/comm"
	"encoding/gob"
	"time"
	log "github.com/golang/glog"
)

//处理redis队列里面的消息
type Core struct {
	manager *db.Manager
	storage_pool *storage.StorageConnPool
	rmq *mq.RedisMQ
}

//处理消息
func (core *Core) HandleMsg(m *comm.Message) {
	//处理消息
	switch m.Cmd {
		case comm.MSG_IM:
			core.HandleIMMessage(m)
		case comm.MSG_GROUP_IM:
			core.HandleGroupMessage(m)
		case comm.MSG_DEVICE_KICK:
			core.HandleDeviceKick(m)
		case comm.MSG_INPUTING:
			core.HandleInputting(m)
		case comm.MSG_ROOM_IM:
			core.HandleRoomMessage(m)
		case comm.MSG_THROUGH_IN:
			core.HandleThrough(m)
		case comm.MSG_FRIEND_ADD:
			core.HandleFriendAdd(m)
		case comm.MSG_FRIEND_DEL:
			core.HandleFriendDel(m)
	}
}

//处理加好友
func (core *Core) HandleFriendAdd(msg *comm.Message) {
	storage, _ := core.storage_pool.Get()
	defer core.storage_pool.Release(storage)
	
	body := msg.Body.(*comm.FriendOp)
	
	m := new(comm.Message)
	
	m.Cmd = comm.MSG_FRIEND_ADDED
	m.Seq = msg.Seq
	m.Version = msg.Version
	
	//建立好友关系
	if !core.manager.BuildFriendShip(comm.APP_ID, body.Sender, body.Receiver) {
		//告诉发送者加好友失败
		SendFriendOpStatusMessage(m, storage, core.rmq, core.manager, body.Receiver, body.Sender, 1)
		return
	}
	
	//成功建立，给两个人都发送信息
	SendFriendOpStatusMessage(m, storage, core.rmq, core.manager, body.Sender, body.Receiver, 0)
	SendFriendOpStatusMessage(m, storage, core.rmq, core.manager, body.Receiver, body.Sender, 0)
}

func SendFriendOpStatusMessage(m *comm.Message, storage *storage.StorageConn, rmq *mq.RedisMQ, manager *db.Manager, sender int64, receiver int64, status int32) {
	resp := new(comm.FriendOpStatus)
	resp.Status = status
	resp.Sender = sender
	resp.Receiver = receiver
	m.Body = resp
	
	//存储消息
	var msgid int64
	err := storage.Conn.Call("StorageServer.SaveCmdMessage", m, &msgid)
	if err != nil {
		log.Error("storage friendopstatus err", err)
		return
	}
	
	//发送消息到指定connect server队列，由connect server负责将消息分发到客户端
	points, err := manager.GetUserLoginPoints(comm.APP_ID, receiver)
	if points == nil || err != nil {
		return
	}
	
	resp = new(comm.FriendOpStatus)
	resp.Status = status
	resp.Sender = sender
	resp.Receiver = receiver
	resp.Msgid = msgid
	m.Body = resp
	
	for _, point := range points {
		if point.Login_srv == "" {
			continue
		}
		
		key := fmt.Sprintf("GIM_MS_S_%s", point.Login_srv)
		rmq.Enqueue(key, m)
	}
}

//处理删好友
func (core *Core) HandleFriendDel(msg *comm.Message) {
	storage, _ := core.storage_pool.Get()
	defer core.storage_pool.Release(storage)
	
	body := msg.Body.(*comm.FriendOp)
	
	m := new(comm.Message)
	
	m.Cmd = comm.MSG_FRIEND_DELED
	m.Seq = msg.Seq
	m.Version = msg.Version
	
	//建立好友关系
	if !core.manager.RemoveFriendShip(comm.APP_ID, body.Sender, body.Receiver) {
		//告诉发送者加好友失败
		SendFriendOpStatusMessage(m, storage, core.rmq, core.manager, body.Receiver, body.Sender, 1)
		return
	}
	
	//成功建立，给两个人都发送信息
	SendFriendOpStatusMessage(m, storage, core.rmq, core.manager, body.Sender, body.Receiver, 0)
	SendFriendOpStatusMessage(m, storage, core.rmq, core.manager, body.Receiver, body.Sender, 0)
}

//处理透传消息
func (core *Core) HandleThrough(msg *comm.Message) {
	
	storage, _ := core.storage_pool.Get()
	defer core.storage_pool.Release(storage)
	
	body := msg.Body.(*comm.ThroughMessageIn)
	
	if body.Targets_len <= 0 {
		return
	}
	
	if body.Target_type == comm.THROUGH_TARGET_USER {
		
		for i:=0; i<int(body.Targets_len); i++ {
			DealThroughMessage(storage, core.manager, core.rmq, body, body.Targets[i], msg.Seq, msg.Version)
		}
		
	} else if body.Target_type == comm.THROUGH_TARGET_GROUP {
		
		for i:=0; i<int(body.Targets_len); i++ {
			//获取群成员
			members := core.manager.GetGroupMemberUids(comm.APP_ID, body.Targets[i])
			for _, uid := range members {
				//不要发给自己
				if int64(uid) == body.Sender {
					continue
				}
				
				DealThroughMessage(storage, core.manager, core.rmq, body, int64(uid), msg.Seq, msg.Version)
			}
		}
		
	} else if body.Target_type == comm.THROUGH_TARGET_ROOM {
		
		for i:=0; i<int(body.Targets_len); i++ {
			//获取聊天室成员
			members := core.manager.GetRoomMemberUids(comm.APP_ID, body.Targets[i])
			for _, uid := range members {
				//不要发给自己
				if int64(uid) == body.Sender {
					continue
				}
				
				DealThroughMessage(storage, core.manager, core.rmq, body, int64(uid), msg.Seq, msg.Version)
			}
		}
		
	}
}

func DealThroughMessage(storage *storage.StorageConn, manager *db.Manager, rmq *mq.RedisMQ, body *comm.ThroughMessageIn, receiver int64, seq int64, version int) {
	m := new(comm.Message)
	
	m.Cmd = comm.MSG_THROUGH_OUT
	m.Seq = seq
	m.Version = version
	
	tmo1 := &comm.ThroughMessageOut{
		Sender : body.Sender,
		Receiver : receiver,
		Timestamp : int32(time.Now().Unix()),
		Msgid     : 0,
		Action   : body.Action,
		Extra     : body.Extra,
	}
	
	m.Body = tmo1
	//存储消息
	var msgid int64
	err := storage.Conn.Call("StorageServer.SaveCmdMessage", m, &msgid)
	if err != nil {
		log.Error("storage saveThrough err", err)
		return
	}
	
	tmo2 := &comm.ThroughMessageOut{
		Sender : tmo1.Sender,
		Receiver : tmo1.Receiver,
		Timestamp : tmo1.Timestamp,
		Msgid     : msgid,
		Action   : tmo1.Action,
		Extra     : tmo1.Extra,
	}
	m.Body = tmo2
	
	//发送消息到指定connect server队列，由connect server负责将消息分发到客户端
	points, err := manager.GetUserLoginPoints(comm.APP_ID, receiver)
	if points == nil || err != nil {
		return
	}
	
	for _, point := range points {
		if point.Login_srv == "" {
			continue
		}
		
		key := fmt.Sprintf("GIM_MS_S_%s", point.Login_srv)
		rmq.Enqueue(key, m)
	}
}

//处理设备互踢
func (core *Core) HandleDeviceKick(msg *comm.Message) {
	
	body := msg.Body.(*comm.DeviceKick)
	//获取用户设备列表
	points, err := core.manager.GetUserLoginPoints(comm.APP_ID, body.Uid)
	if err != nil {
		return
	}
	//往当前所有设备发送踢掉消息，并且移除设备信息
	for _, point := range points {
		if point.Device_id == body.Device_id {
			continue
		}
		
		key := fmt.Sprintf("GIM_MS_S_%s", point.Login_srv)
		core.rmq.Enqueue(key, msg)
		
		core.manager.RemoveUserLoginPoint(comm.APP_ID, body.Uid, point.Device_id)
	}
}

//处理输入消息
func (core *Core) HandleInputting(msg *comm.Message) {	
	//发送消息到指定connect server队列，由connect server负责将消息分发到客户端
	body := msg.Body.(*comm.MessageInputing)
	
	//发送消息到指定connect server队列，由connect server负责将消息分发到客户端
	points, err := core.manager.GetUserLoginPoints(comm.APP_ID, body.Receiver)
	if points == nil || err != nil {
		return
	}
	
	for _, point := range points {
		if point.Login_srv == "" {
			continue
		}
		
		key := fmt.Sprintf("GIM_MS_S_%s", point.Login_srv)
		core.rmq.Enqueue(key, msg)
	}
}

//处理普通聊天消息
func (core *Core) HandleIMMessage(m *comm.Message) {	
	storage, _ := core.storage_pool.Get()
	defer core.storage_pool.Release(storage)
	
	body := m.Body.(*comm.IMMessage)
	
	//判断是否在对方黑名单里
	if core.manager.IsUserBlack(comm.APP_ID, body.Receiver, body.Sender) {
		return
	}
	
	//存储消息
	var msgid int64
	err := storage.Conn.Call("StorageServer.SaveMessage", m, &msgid)
	if err != nil {
		log.Error("storage save err", err)
		return
	}
	
	msg := new(comm.Message)
	
	msg.Cmd = m.Cmd
	msg.Seq = m.Seq
	msg.Version = m.Version
	
	msg.Body = &comm.IMMessage{
		Sender : body.Sender,
		Receiver : body.Receiver,
		Gid		 : body.Gid,
		Timestamp : body.Timestamp,
		Msgid     : msgid,
		Content   : body.Content,
		Extra     : body.Extra,
	}
	
	//发送消息到指定connect server队列，由connect server负责将消息分发到客户端
	points, err := core.manager.GetUserLoginPoints(comm.APP_ID, body.Receiver)
	if points == nil || err != nil {
		return
	}
	
	for _, point := range points {
		if point.Login_srv == "" {
			continue
		}
		
		key := fmt.Sprintf("GIM_MS_S_%s", point.Login_srv)
		core.rmq.Enqueue(key, msg)
	}
}

//处理群组聊天消息
func (core *Core) HandleGroupMessage(m *comm.Message) {
	body := m.Body.(*comm.IMMessage)
	//获取群成员
	members := core.manager.GetGroupMemberUids(comm.APP_ID, body.Receiver)
	for _, uid := range members {
		//不要发给自己
		if int64(uid) == body.Sender {
			continue
		}
		
		m1 := &comm.Message{
			Cmd : m.Cmd,
			Seq : m.Seq,
			Version: m.Version,
		}
	
		//发给每一个成员
		msg := new(comm.IMMessage)
		msg.Sender = body.Sender
		msg.Receiver = int64(uid)
		msg.Gid = body.Gid
		msg.Timestamp = body.Timestamp
		msg.Content = body.Content
		msg.Extra = body.Extra
		
		m1.Body = msg
		
		core.HandleIMMessage(m1)
	}
}

//处理聊天室聊天消息
func (core *Core) HandleRoomMessage(m *comm.Message) {
	body := m.Body.(*comm.IMMessage)
	//获取聊天室成员
	members := core.manager.GetRoomMemberUids(comm.APP_ID, body.Receiver)
	for _, uid := range members {
		//不要发给自己
		if int64(uid) == body.Sender {
			continue
		}
		
		m1 := &comm.Message{
			Cmd : m.Cmd,
			Seq : m.Seq,
			Version: m.Version,
		}
	
		//发给每一个成员
		msg := new(comm.IMMessage)
		msg.Sender = body.Sender
		msg.Receiver = int64(uid)
		msg.Gid = body.Gid
		msg.Timestamp = body.Timestamp
		msg.Content = body.Content
		msg.Extra = body.Extra
		
		m1.Body = msg
		
		core.HandleIMMessage(m1)
	}
}

func StartCore(db_host string, db_password string, mq_host string, mq_password string, storage_host string) *Core{
	
	comm.InitMessage()
	
	core := &Core{}
	
	//创建storage连接池
	f := storage.DialStorageFun(storage_host)
	core.storage_pool = storage.NewStorageConnPool(100, 500, 600 * time.Second, f)
	
	core.manager = db.NewManager(db_host, db_password)
	
	core.rmq = mq.NewRedisMQ(mq_host, mq_password)
	
	gob.Register(comm.IMMessage{})
	
	go func(){
		for {	
			msg := core.rmq.BDequeue("GIM_MS_Q")
			if msg == nil {
				continue
			}
			
			core.HandleMsg(msg)
		}
	}()
	
	return core
}

func StopCore(core *Core) {
	mq.StopRedisMQ(core.rmq)
	db.StopManager(core.manager)
}